<?php
/**
 * DBShop 电子商务系统
 *
 * ==========================================================================
 * @link      https://www.dbshop.net/
 * @copyright 北京珑大钜商科技有限公司，并保留所有权利。
 * @license   https://www.dbshop.net/license.html License
 * ==========================================================================
 *
 * @author    静静的风 <baron@loongdom.cn>
 *
 */

namespace Admin\Service\Payment;

use Admin\Data\Common;
use Laminas\Config\Writer\PhpArray;
use Laminas\Session\Container;
use Yansongda\Pay\Pay;

class WxpayService
{
    private $config     = [];
    private $wxpayConfig= [];
    private $orderSession;

    public function __construct()
    {
        if(!$this->config) {
            $this->config = Common::getPaymentConfig('wxpay');
        }
        $this->orderSession     = new Container('wxPaySession');

        $this->wxpayConfig = [
            'appid'     => $this->config['paymentMobileAppId']['content'],  //移动应用AppId
            'app_id'    => $this->config['paymentAppId']['content'],        //公众号AppId
            'miniapp_id'=> $this->config['paymentMinAppId']['content'],     //小程序的AppId
            'mch_id'    => $this->config['paymentMchId']['content'],        //商户号
            'key'       => $this->config['paymentKey']['content']           //支付的key
        ];
    }

    public function savePaymentConfig(array $data, $paymentConfig, $configFile)
    {
        $configArray = PaymentForm::setFormValue($paymentConfig, $data);

        $write = new PhpArray();
        $write->setUseBracketArraySyntax(true);
        $write->toFile($configFile, $configArray);

        Common::opcacheInvalidate($configFile);
    }

    public function getFormInput($paymentConfig)
    {
        return PaymentForm::createFormInput($paymentConfig);
    }

    /**
     * 微信支付，包含H5支付、公众号支付、扫码支付
     * @param array $data
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function orderPaymentTo(array $data)
    {
        $orderInfo = $data['orderInfo'];
        $goodsArray= $orderInfo->getOrderGoods();

        $this->wxpayConfig['notify_url'] = $data['notifyUrl'];
        $this->wxpayConfig['return_url'] = $data['returnUrl'];

        $order = [
            'attach'        => $orderInfo->getOrderSn(),
            'out_trade_no'  => str_pad(mt_rand(1, 999), 3, '0', STR_PAD_LEFT).'Sn'.$orderInfo->getOrderSn(),
            'fee_type'      => $orderInfo->getCurrencyCode(),
            'total_fee'     => $orderInfo->getOrderAmount() * 100,
            'body'          => (count($goodsArray) == 1 ? $goodsArray[0]->getGoodsName() : '多商品合并购买')
        ];

        $this->orderSession->offsetSet('out_trade_no', $order['out_trade_no']);

        //下面为公众号支付、扫码支付、H5支付
        $isWechat       = Common::isWeixin();//是否在微信内
        $isMobile       = Common::isMobile();//是否为移动端
        if (!$isWechat && !$isMobile) {
            //扫码支付使用 模式二
            // 二维码内容： $qr = $result->code_url;
            return ['type' => 'scan', 'result' => Pay::wechat($this->wxpayConfig)->scan($order)];
        } else {
            if ($isWechat) {//公众号支付
                $order['openid'] = Common::getWechatOpenId(['wxAppId' => $this->config['paymentAppId']['content'], 'wxAppSecret' => $this->config['paymentAppSecret']['content'], 'redirectUrl' => $data['wxReturnUrl']]);
                // 返回 Collection 实例。包含了调用 JSAPI 的所有参数，如appId，timeStamp，nonceStr，package，signType，paySign 等；
                // 可直接通过 $result->appId, $result->timeStamp 获取相关值。
                // 后续调用不在本文档讨论范围内，请自行参考官方文档。
                return ['type' => 'wechat', 'result' => Pay::wechat($this->wxpayConfig)->mp($order)];
            }

            return Pay::wechat($this->wxpayConfig)->wap($order)->send();//移动端H5支付
        }
    }


    public function orderToSend(array $data)
    {

    }

    /**
     * 支付返回
     * @param $orderInfo
     * @return array
     * @throws \Yansongda\Pay\Exceptions\GatewayException
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
     * @throws \Yansongda\Pay\Exceptions\InvalidSignException
     */
    public function orderPaymentReturn($orderInfo)
    {
        $wxPay = Pay::wechat($this->wxpayConfig);
        $result = $wxPay->find(['out_trade_no' => $this->orderSession->offsetGet('out_trade_no')]);
        $this->orderSession->getManager()->getStorage()->clear($this->orderSession->getName());

        return ['paymentStatus' => ($result->offsetGet('trade_state') == 'SUCCESS' ? true : false), 'orderAmount' => $orderInfo->getOrderAmount()];
    }

    /**
     * 支付异步通知
     * @param $orderInfo
     * @return array
     */
    public function orderPaymentNotify($orderInfo)
    {
        $wxPay = Pay::wechat($this->wxpayConfig);

        try {
            $result = $wxPay->verify();
            if (
                $result->offsetGet('result_code') == 'SUCCESS'
                && $result->offsetGet('total_fee') == $orderInfo->getOrderAmount() * 100
                && $result->offsetGet('attach') == $orderInfo->getOrderSn()
            )
            {
                //查看是否已经支付完毕
                if($orderInfo->getOrderStatus() >= Common::orderStatusCode('WAIT_GOODS_ARRIVE')) return ['finishPay' => true, 'orderAmount' => $orderInfo->getOrderAmount(), 'sendMessage' => $wxPay->success()->getContent()];

                return ['paymentStatus' => true, 'outTradeNo' => $result->offsetGet('out_trade_no'), 'orderAmount' => $orderInfo->getOrderAmount(), 'sendMessage' => $wxPay->success()->getContent()];
            }
        } catch (\Exception $e) {
            //$e->getMessage();
        }
        //return $wxPay->success()->send();
        return ['paymentStatus' => false, 'sendMessage' => ''];
    }

    /**
     * 支付
     * @param array $data
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function paymentTo(array $data)
    {
        $this->wxpayConfig['notify_url'] = $data['notifyUrl'];
        $this->wxpayConfig['return_url'] = $data['returnUrl'];

        $info = [
            'attach'        => $data['sn'],
            'out_trade_no'  => str_pad(mt_rand(1, 999), 3, '0', STR_PAD_LEFT).$data['sn'],
            'fee_type'      => $data['currency'],
            'total_fee'     => $data['amount'] * 100,
            'body'          => $data['subject']
        ];

        $this->orderSession->offsetSet('out_trade_no', $info['out_trade_no']);

        //下面为公众号支付、扫码支付、H5支付
        $isWechat       = Common::isWeixin();//是否在微信内
        $isMobile       = Common::isMobile();//是否为移动端
        if (!$isWechat && !$isMobile) {
            //扫码支付使用 模式二
            // 二维码内容： $qr = $result->code_url;
            return ['type' => 'scan', 'result' => Pay::wechat($this->wxpayConfig)->scan($info)];
        } else {
            if ($isWechat) {//公众号支付
                $info['openid'] = Common::getWechatOpenId(['wxAppId' => $this->config['paymentAppId']['content'], 'wxAppSecret' => $this->config['paymentAppSecret']['content'], 'redirectUrl' => $data['wxReturnUrl']]);
                // 返回 Collection 实例。包含了调用 JSAPI 的所有参数，如appId，timeStamp，nonceStr，package，signType，paySign 等；
                // 可直接通过 $result->appId, $result->timeStamp 获取相关值。
                // 后续调用不在本文档讨论范围内，请自行参考官方文档。
                return ['type' => 'wechat', 'result' => Pay::wechat($this->wxpayConfig)->mp($info)];
            }

            return Pay::wechat($this->wxpayConfig)->wap($info)->send();//移动端H5支付
        }
    }

    /**
     * 支付返回
     * @param array $data
     * @return array
     * @throws \Yansongda\Pay\Exceptions\GatewayException
     * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException
     * @throws \Yansongda\Pay\Exceptions\InvalidSignException
     */
    public function paymentReturn(array $data)
    {
        $wxPay = Pay::wechat($this->wxpayConfig);
        $result = $wxPay->find(['out_trade_no' => $this->orderSession->offsetGet('out_trade_no')]);
        $this->orderSession->getManager()->getStorage()->clear($this->orderSession->getName());

        return ['paymentStatus' => ($result->offsetGet('result_code') == 'SUCCESS' ? true : false), 'orderAmount' => $data['amount']];
    }

    /**
     * 支付异步
     * @param array $data
     * @return array
     */
    public function paymentNotify(array $data)
    {
        $wxPay = Pay::wechat($this->wxpayConfig);

        try {
            $result = $wxPay->verify();
            if (
                $result->offsetGet('result_code') == 'SUCCESS'
                && $result->offsetGet('total_fee') == $data['amount'] * 100
                && $result->offsetGet('attach') == $data['sn']
            )
            {
                //查看是否已经支付完毕
                if($data['status'] >= 20) return ['finishPay' => true, 'amount' => $data['amount'], 'sendMessage' => $wxPay->success()->getContent()];

                return ['paymentStatus' => true, 'amount' => $data['amount'], 'sendMessage' => $wxPay->success()->getContent()];
            }
        } catch (\Exception $e) {
            //$e->getMessage();
        }
        //return $wxPay->success()->send();
        return ['paymentStatus' => false, 'sendMessage' => ''];
    }
}